﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Zcold.ZcoldString;

namespace SimulinkParser
{
	/// <summary> Static .mdl file manipulation methods
	/// </summary>
	public static class FileManipulation
	{
		/// <summary> Read .mdl file to ParameterBlock format
		/// </summary>
		/// <param name="FilePath"> Path of the .mdl file </param>
		/// <returns> ParameterBlock instance for further usage </returns>
		public static ParameterBlock ReadFile(string FilePath)
		{
			StreamReader Reader = new StreamReader(FilePath);
			string CurrentLine = Reader.ReadLine();
			CurrentLine = CurrentLine.PurgeCharList(new List<char>() { '\t', ' ', '{' });
			return ReadParameterBlock(ref Reader, CurrentLine);
		}

		/// <summary> Read one ParameterBlock from a .mdl file which is opened with a speicified StreamReader.
		/// </summary>
		/// <param name="Reader"> The specified SteamReader </param>
		/// <param name="Title"> The title of this ParameterBlock </param>
		/// <returns> ParameterBlock instance for further usage </returns>
		public static ParameterBlock ReadParameterBlock(ref StreamReader Reader, string Title)
		{
			ParameterBlock Result = new ParameterBlock();
			string CurrentLine = "";

			Result.Title = Title;

			while ((CurrentLine = Reader.ReadLine()) != null)
			{
				if (CurrentLine.Contains("{"))
				{
					CurrentLine = CurrentLine.PurgeCharList(new List<char>() { '\t', ' ', '{' });
					Result.Childs.Add(ReadParameterBlock(ref Reader, CurrentLine));
				}
				else
				{
					if (CurrentLine.Contains("}"))
						return Result;

					Result.Parameters.Add(new SimulinkParameter(CurrentLine));
				}
			}

			return Result;
		}

		/// <summary> Extract SimulinkSystem data sturcture from a given ParameterBlock instance
		/// </summary>
		/// <param name="FileModel"> The given ParameterBlock instance </param>
		/// <returns> SimulinkSystem instance </returns>
		public static SimulinkSystem ExtractSimulinkModelFromFileModel(ParameterBlock FileModel)
		{
			SimulinkSystem Model = new SimulinkSystem();

			ParameterBlock DefaultBlock = FileModel.BlockParameterDefaults;
			ParameterBlock System = FileModel.System;
			ParameterList Parameters = FileModel.Parameters;

			Model.Parameters = FileModel.Parameters;

			return Model;
		}

		/// <summary> Extract SimulinkBlock set from a specified ParamterBlock
		/// </summary>
		/// <param name="FileModel"> Given ParameterBlock instance </param>
		/// <returns> List&lt;SimulinkBlock&gt; instance</returns>
		public static List<SimulinkBlock> ExtractSimulinkBlockListFromFileModel(ParameterBlock FileModel)
		{
			List<SimulinkBlock> Result = new List<SimulinkBlock>();

			foreach (ParameterBlock PB in FileModel.BlockChilds)
			{
				Console.WriteLine("Find one block.");
				Result.Add(ExtractSimulinkBlockFromFileModel(PB));
			}
			return Result;
		}

		/// <summary> Extract SimulinkBlock from a specified ParamterBlock
		/// </summary>
		/// <param name="BlockFileModel"> Given ParameterBlock instance </param>
		/// <returns> SimulinkBlock instance</returns>
		public static SimulinkBlock ExtractSimulinkBlockFromFileModel(ParameterBlock BlockFileModel)
		{
			SimulinkBlock Block = new SimulinkBlock();

			Block.Parameters = BlockFileModel.Parameters;

			if (BlockFileModel.ContainsSystem)
				Block.System = ExtractSimulinkSystemFromFileModel(BlockFileModel.System);

			return Block;
		}

		/// <summary> Extract SimulinkLine from a specified ParamterBlock
		/// </summary>
		/// <param name="LineFileModel"> Given ParameterBlock instance </param>
		/// <returns> SimulinkLine instance</returns>
		public static SimulinkLine ExtractSimulinkLineFromFileModel(ParameterBlock LineFileModel)
		{
			SimulinkLine Result = new SimulinkLine();
			string SourceName = LineFileModel.SrcBlock;
			string SourcePort = LineFileModel.SrcPort;

			string DestinationName;
			string DestinationPort;

			Result.Source = new End(SourceName, SourcePort);
			Result.Destination = new List<End>();

			if (!LineFileModel.ContainsBranch) // Single destination
			{
				DestinationName = LineFileModel.DstBlock;
				DestinationPort = LineFileModel.DstPort;


				Result.Destination.Add(new End(DestinationName, DestinationPort));
			}
			else // Multiple destination
			{
				foreach (ParameterBlock PB in LineFileModel.BranchChilds)
				{
					DestinationName = PB.DstBlock;
					DestinationPort = PB.DstPort;
					Result.Destination.Add(new End(DestinationName, DestinationPort));
				}
			}

			return Result;
		}

		/// <summary> Extract SimulinkLine set from a specified ParamterBlock
		/// </summary>
		/// <param name="LineFileModel"> Given ParameterBlock instance </param>
		/// <returns> List&lt;SimulinkLine&gt; instance</returns>
		public static List<SimulinkLine> ExtractSimulinkLineListFromFileModel(ParameterBlock LineFileModel)
		{
			List<SimulinkLine> Lines = new List<SimulinkLine>();

			foreach (ParameterBlock PB in LineFileModel.LineChilds)
			{
				Console.WriteLine("Found one line");
				Lines.Add(ExtractSimulinkLineFromFileModel(PB));
			}

			return Lines;
		}

		/// <summary> Extract SimulinkSystem from a specified ParamterBlock
		/// </summary>
		/// <param name="SystemFileModel"> Given ParameterBlock instance </param>
		/// <returns> SimulinkSystem instance</returns>
		public static SimulinkSystem ExtractSimulinkSystemFromFileModel(ParameterBlock SystemFileModel)
		{
			SimulinkSystem System = new SimulinkSystem();
			Console.WriteLine("Extracting System");
			System.Parameters = SystemFileModel.Parameters;

			if (SystemFileModel.ContainsBlock)
			{
				Console.WriteLine("Extracting blocks ...");
				System.Blocks = ExtractSimulinkBlockListFromFileModel(SystemFileModel);
			}

			if (SystemFileModel.ContainsLine)
			{
				Console.WriteLine("Extracting lines ...");
				System.Lines = ExtractSimulinkLineListFromFileModel(SystemFileModel);
			}

			return System;

		}
	}
}
